/*******************************************************************************
 * Includes
 ******************************************************************************/
#include "Wed_netdev.h"

/*******************************************************************************
 * Static
 ******************************************************************************/
static struct Wed_list_head __g_netdev_list;
static struct Wed_mutex     __g_netdev_list_lock;

/*******************************************************************************
 * Code
 ******************************************************************************/
/**
 * \brief 网络设备链表初始化
 *
 * @return 成功返回 0
 */
int Wed_netdev_list_init(void){
    Wed_list_head_init(&__g_netdev_list);

    return Wed_mutex_init(&__g_netdev_list_lock);
}

/**
 * \brief 设备添加函数
 */
static int __dev_add(struct Wed_netdev *p_netdev){
    int ret = 0;

    ret = Wed_mutex_lock(&__g_netdev_list_lock, 5000);
    if (ret != 0) {
        return ret;
    }

    Wed_list_node_add_tail(&p_netdev->node, &__g_netdev_list);

    Wed_mutex_unlock(&__g_netdev_list_lock);

    return ret;
}

/**
 * \brief 网络设备写函数
 */
static int __dev_init(void *p_dev){
    struct Wed_netdev *p_netdev = (struct Wed_netdev *)p_dev;

    if (p_netdev->p_opts->p_fn_init) {
        return p_netdev->p_opts->p_fn_init(p_netdev->p_opts_arg);
    }

    return 0;
}

/* \brief 设备操作函数集 */
static struct Wed_dev_opts __g_netdev_opts = {

};

/**
 * \brief 网络设备注册函数
 *
 * @param p_net_name 网络设备名字
 * @param p_opts     网络设备操作函数集
 * @param p_opts_arg 操作函数参数
 *
 * @return 成功返回 0
 */
int Wed_netdev_register(char                   *p_net_name,
                        struct Wed_netdev_opts *p_opts,
                        void                   *p_opts_arg){
    int                ret;
    struct Wed_netdev *p_netdev = NULL;

    if ((p_net_name == NULL) ||
            (strlen(p_net_name) >= WED_DEV_NAME_LEN) ||
            (p_opts == NULL)) {
        return -WED_EINVAL;
    }

    /* 检查设备是否已存在 */
    if (Wed_dev_find_by_name(p_net_name)) {
        return -WED_EEXIST;
    }

#if WED_MEM_DYMANICS
    p_netdev = Wed_calloc(1, sizeof(struct Wed_netdev));
    if (p_netdev == NULL) {
        return -WED_ENOMEM;
    }

    p_netdev->p_opts     = p_opts;
    p_netdev->p_opts_arg = p_opts_arg;
    //p_uart_dev->flag       = flag;

    ret = Wed_mutex_init(&p_netdev->lock);
    if (ret != 0) {
        goto __failed;
    }

    ret = Wed_dev_init_add(&p_netdev->dev,
                            p_net_name,
                            WED_DEV_TYPE_NETDEV,
                         &__g_netdev_opts,
                            p_netdev);
    if (ret == 0) {
        __dev_add(p_netdev);

        return 0;
    }

__failed:
    Wed_free(p_netdev);

    return ret;
#else

#endif
}

/**
 * \brief 初始化所有网络设备
 *
 * @return 成功返回 0
 */
int Wed_netdev_init_all(void){
    int                   ret;
    int                   result = 0;
    struct Wed_list_node *p_node = NULL;
    struct Wed_netdev    *p_dev  = NULL;

    result = Wed_mutex_lock(&__g_netdev_list_lock, 5000);
    if (result != 0) {
        return result;
    }

    Wed_list_for_each_node(p_node, &__g_netdev_list){
        p_dev = WED_CONTAINER_OF(p_node, struct Wed_netdev, node);

        ret = __dev_init(p_dev);
        if (ret != 0) {
            WED_WARN_PRINT("netdev \"%s\" init failed(%d)", p_dev->dev.name);
        } else {
            WED_INFO_PRINT("netdev \"%s\" init success", p_dev->dev.name);
        }
        result |= ret;
    }

    Wed_mutex_unlock(&__g_netdev_list_lock);

    return result;
}

/**
 * \brief 根据名字获取网络设备结构体
 *
 * @param p_net_name 网络设备名字
 *
 * @return 找到返回网络设备结构体，没找到返回 NULL
 */
struct Wed_netdev *Wed_netdev_find_by_name(char *p_net_name){
    int                   ret;
    struct Wed_list_node *p_node = NULL;
    struct Wed_netdev    *p_dev  = NULL;

    ret = Wed_mutex_lock(&__g_netdev_list_lock, 5000);
    if (ret != 0) {
        return NULL;
    }

    Wed_list_for_each_node(p_node, &__g_netdev_list){
        p_dev = WED_CONTAINER_OF(p_node, struct Wed_netdev, node);
        if (strcmp(p_dev->dev.name, p_net_name) == 0) {
            Wed_mutex_unlock(&__g_netdev_list_lock);

            return p_dev;
        }
    }

    Wed_mutex_unlock(&__g_netdev_list_lock);

    return NULL;
}


/**
 * \brief 网络设备原始输出函数
 *
 * @param p_netdev 相关网络设备结构体
 * @param p_data   要写的数据缓存
 * @param data_len 要写的数据长度
 *
 * @return 成功返回 0
 */
int Wed_netdev_raw_output(struct Wed_netdev *p_netdev,
                          uint8_t           *p_data,
                          uint16_t           data_len){
    int      ret;

    if ((p_netdev == NULL) ||
            (p_data == NULL) ||
            (data_len == 0)) {
        return -WED_EINVAL;
    }

    if (p_netdev->p_opts->p_fn_raw_output == NULL) {
        return -WED_ENOSUPPORT;
    }

    ret = Wed_mutex_lock(&p_netdev->lock, 5000);
    if (ret != 0) {
        return ret;
    }

    ret = p_netdev->p_opts->p_fn_raw_output(p_netdev->p_opts_arg, p_data, data_len);

    Wed_mutex_unlock(&p_netdev->lock);

    return ret;
}
